﻿#include "stdafx.h"



//com ole
//#include <comdef.h>
//#include <commdlg.h>

#include <shlwapi.h> ///QISearch



#include "qrichedit.h"
using namespace micro::gui;


//FINDREPLACE fr;       // common dialog box structure
//HWND hwnd;            // owner window
//CHAR szFindWhat[80];  // buffer receiving string
//HWND hdlg = nullptr;     // handle to Find dialog box
//
//// Initialize FINDREPLACE
//ZeroMemory(&fr, sizeof(fr));
//fr.lStructSize = sizeof(fr);
//fr.hwndOwner = hwnd;
//fr.lpstrFindWhat = szFindWhat;
//fr.wFindWhatLen = 80;
//fr.Flags = 0;
//
//hdlg = FindText(&fr);



QRichEdit::QRichEdit()
{

    //m_pRichEditOle  = nullptr;
    m_pRECallback = nullptr;


    m_hLib  = LoadLibrary( _T( "msftedit.dll" ) );

    if ( !m_hLib )
    {
        //Message("MSFTEDIT.DLL Didn't Load");
        return ;
    }

    //memset(&m_psdPage, 0, sizeof (m_psdPage));
    m_hDevMode		= nullptr;
    m_hDevNames		= nullptr;
    m_nPrinterWidth	= 0;
}

QRichEdit::~QRichEdit( void )
{
    if ( m_pRECallback )
        m_pRECallback->Release();


    if ( m_hLib )
        FreeLibrary( m_hLib );
}




bool QRichEdit::Create( QWindow * parent, int id,  UINT style )
{


    //Set Options for the Rich Edit Control
    DWORD dwStyle = style
                    | WS_CHILD
                    | WS_VISIBLE
                    | WS_CLIPSIBLINGS
                    | WS_VSCROLL

                    //| ES_AUTOVSCROLL
                    //| WS_HSCROLL
                    //| ES_AUTOHSCROLL
                    | ES_MULTILINE;

    bool bo  = CreateBaseWindowEx( 0, MSFTEDIT_CLASS , nullptr,
                                   dwStyle,
                                   QRect(),
                                   parent, id );




    m_pRECallback = new QOleCallback( GetHandle() );
    SetOleCallback( m_pRECallback );
    m_pRECallback->AddRef();




// 		IRichEditOle* pRichEditOle = nullptr;
// 		GetOleInterface(&pRichEditOle);
// 		if (pRichEditOle)
// 		{
// 			pRichEditOle->SetHostNames( "myco" ,  "myco-rtf");
// 			pRichEditOle->Release();
// 		}



    return bo;

}





int QRichEdit::GetPrinterWidth( HDC hdcPrn )
{
    HDC hdcScr	= GetDC( 0 );

    int nPrinterDPI		= GetDeviceCaps( hdcPrn, LOGPIXELSX );
    int nPrinterWidth	= GetDeviceCaps( hdcPrn, HORZRES );
    int nScreenDPI		= GetDeviceCaps( hdcScr, LOGPIXELSX );

    ReleaseDC( 0, hdcScr );

    return nPrinterWidth * nScreenDPI / nPrinterDPI;
}




HDC QRichEdit::GetDefaultPrinterDC()
{
    PRINTDLG pdlg	= { sizeof( pdlg ),  0, 0, 0 };
    pdlg.Flags		= PD_RETURNDC | PD_RETURNDEFAULT;

    if ( PrintDlg( &pdlg ) )
    {
        m_hDevMode		= pdlg.hDevMode;
        m_hDevNames		= pdlg.hDevNames;
        return pdlg.hDC;
    }
    else
    {
        return nullptr;
    }
}
int QRichEdit::GetCurrentPrinterWidth()
{
    if ( m_nPrinterWidth == 0 )
    {
        HDC hdcPrn		= GetDefaultPrinterDC();
        m_nPrinterWidth = GetPrinterWidth( hdcPrn );

        DeleteDC( hdcPrn );
    }

    return m_nPrinterWidth;
}
HDC QRichEdit::ShowPrintDialog( HWND hwndParent )
{
    PRINTDLGEX	pdlgx	= { sizeof( pdlgx ), hwndParent, m_hDevMode, m_hDevNames };
    pdlgx.Flags			= PD_RETURNDC | PD_NOPAGENUMS | PD_NOCURRENTPAGE | PD_NOWARNING | PD_HIDEPRINTTOFILE;
    pdlgx.nStartPage	= START_PAGE_GENERAL;

    if ( S_OK == PrintDlgEx( &pdlgx ) && pdlgx.dwResultAction != PD_RESULT_CANCEL )
    {
        m_hDevMode		= pdlgx.hDevMode;
        m_hDevNames		= pdlgx.hDevNames;
        m_nPrinterWidth = GetPrinterWidth( pdlgx.hDC );

        return pdlgx.hDC;
    }

    return nullptr;
}







bool QRichEdit::PageSetup()
{
    memset( &m_psdPage, 0, sizeof ( m_psdPage ) );


    HWND hwnd = GetHandle();

    m_psdPage.rtMargin.left = 1000;
    m_psdPage.rtMargin.right = 1000;
    m_psdPage.rtMargin.top = 1000;
    m_psdPage.rtMargin.bottom = 1000;
    m_psdPage.Flags = PSD_INHUNDREDTHSOFMILLIMETERS;

    m_psdPage.lStructSize        = sizeof( PAGESETUPDLG );
    m_psdPage.hwndOwner          = hwnd;
    m_psdPage.Flags             |= PSD_MARGINS; //|PSD_ENABLEPAGESETUPHOOK;
    //psdPage.lpfnPageSetupHook  = (LPPAGESETUPHOOK) PrintPageSetupDlgProc;


    ///Starting with Windows Vista, the PageSetupDlg does not contain the Printer button. To switch printer selection, use PrintDlg or PrintDlgEx.
    return  toBool( PageSetupDlg( &m_psdPage ) );
}


bool  QRichEdit::PrintDocument( bool  silent  /* = false*/ )
{

    HDC hdc =  nullptr;

    if ( silent )
    {
        hdc = GetDefaultPrinterDC();
    }
    else
    {
        hdc = ShowPrintDialog(  GetHandle() );
    }


    if ( ! hdc ) return false;

    //do not forget to delete DC


    DOCINFO di = { sizeof( di ), 0 };

    if ( ! StartDoc( hdc, &di ) )	return false;



    int logx			= GetDeviceCaps( hdc, LOGPIXELSX );
    int logy			= GetDeviceCaps( hdc, LOGPIXELSY );

    int cxPhysOffset	= GetDeviceCaps( hdc, PHYSICALOFFSETX );
    int cyPhysOffset	= GetDeviceCaps( hdc, PHYSICALOFFSETY );

    int cxPhys			= GetDeviceCaps( hdc, PHYSICALWIDTH );
    int cyPhys			= GetDeviceCaps( hdc, PHYSICALHEIGHT );

    int rezx			= GetDeviceCaps( hdc, HORZRES );
    int rezy			= GetDeviceCaps( hdc, VERTRES );



    //SendMessage( EM_SETTARGETDEVICE, nullptr, 0);// will wrap text to the window,
    //SendMessage( EM_SETTARGETDEVICE, nullptr, 1);// will disable word-wrap entirely



    // Create "print preview".
    //SendMessage(EM_SETTARGETDEVICE, (WPARAM)hdc, cxPhys);


    int twips = 1440;		//1 inch * 1440 = 1440 twips
    int pas = 0.5 * twips;	//0.5 inch exprimat in twips

    int	left = pas;
    int	top = pas;


    FORMATRANGE fr;
    fr.hdc			= hdc;
    fr.hdcTarget	= hdc;
    fr.rc.left		= left;
    fr.rc.top		= top;


    fr.rc.right  = ::MulDiv( cxPhys, twips, logx )  -  pas;
    fr.rc.bottom = ::MulDiv( cyPhys, twips, logy )  -  pas;

    //echivalent
    //fr.rc.right  =  (cxPhys / logx) * twips -  pas;
    //fr.rc.bottom =  (cyPhys / logy) * twips -  pas;





    GetSel( fr.chrg );								//Get the selection into a CHARRANGE.
    bool noSel = fr.chrg.cpMin == fr.chrg.cpMax;


    if ( noSel )
    {
        //select all

        SetRedraw( false );
        SetSel( 0, -1 );			     //Select the entire contents.
        GetSel( fr.chrg );				//Get the selection into a CHARRANGE.
        SetSel( 0, 0 );
        SetRedraw( true );

    }



    bool fSuccess = true;
    LONG cpMin = 0;

    //Use GDI to print successive pages.
    while ( fSuccess && ( fr.chrg.cpMin <   fr.chrg.cpMax ) )
    {
        fSuccess = StartPage( hdc ) > 0;

        if ( !fSuccess ) break;

        cpMin = ( LONG )SendMessage( EM_FORMATRANGE, 1, ( LPARAM )&fr ); // message returns the index of the last character that fits in the region, plus 1.

        if ( cpMin <= fr.chrg.cpMin )
        {
            fSuccess = false;
            break;
        }

        fr.chrg.cpMin = cpMin;
        fSuccess = EndPage( hdc ) > 0;
    }


    //eliberare de resurse alocate
    SendMessage( EM_FORMATRANGE, 0, 0 );


    if ( fSuccess )
        EndDoc( hdc );
    else
        AbortDoc( hdc );


    ::DeleteDC( hdc );
    return fSuccess;
}






bool QRichEdit::SetOleCallback( IRichEditOleCallback * cb )
{
    ///calls AddRef
    return ( bool ) 0 != SendMessage( EM_SETOLECALLBACK, 0, ( LPARAM ) cb );
}

void QRichEdit::SetModify( bool set )
{
    SendMessage( EM_SETMODIFY, set ? 1 : 0 );
}

bool QRichEdit::GetOleInterface( IRichEditOle ** ppOleInterface )
{
    ///calls AddRef
    return ( bool ) 0 != SendMessage( EM_GETOLEINTERFACE, 0, ( LPARAM ) ( LPVOID )  ppOleInterface );
}

bool QRichEdit::GetModify()
{
    return ( bool ) 0 != SendMessage( EM_GETMODIFY );
}
void QRichEdit::SetBkColor( QCOLOR col )
{
    SendMessage( EM_SETBKGNDCOLOR,   0, ( LPARAM )col );
}


void QRichEdit::ResetBkColor(  )
{
    SendMessage( EM_SETBKGNDCOLOR, 1, 0 ); //reset bkcolor to system color
}



//If the cpMin and cpMax members are equal, the range is empty.
//The range includes everything if cpMin is 0 and cpMax is –1.
void QRichEdit::SetSel( long nStartChar, long nEndChar )
{
    m_crange.cpMin = nStartChar;
    m_crange.cpMax = nEndChar;
    SendMessage( EM_EXSETSEL, 0, ( LPARAM )& m_crange );
}

void QRichEdit::SetSel( CHARRANGE & cr )
{
    m_crange = cr;
    SendMessage( EM_EXSETSEL, 0, ( LPARAM )& cr );
}



void QRichEdit::GetSel( CHARRANGE & cr )
{

    SendMessage( EM_EXGETSEL, 0, ( LPARAM )& cr );
}



void QRichEdit::SetText( QString csText, int nSTFlags, int nSTCodepage )
{
    m_stext.codepage = nSTCodepage;
    m_stext.flags = nSTFlags;
    SendMessage( EM_SETTEXTEX, ( WPARAM )&m_stext, ( LPARAM )( LPCTSTR )csText );
}





bool QRichEdit::SetDefaultCharFormat( DWORD dwMask, COLORREF crTextColor, DWORD dwEffects, LPTSTR  szFaceName, LONG yHeight, COLORREF crBackColor )
{
    //Set the text defaults.  CHARFORMAT2 m_cfStatus is declared in RichEditControl50W.h

    m_cformat.cbSize = sizeof( CHARFORMAT2 );
    m_cformat.dwMask = dwMask ;
    m_cformat.crTextColor = crTextColor;
    m_cformat.dwEffects = dwEffects;
    _tcscpy_s( m_cformat.szFaceName, szFaceName );
    m_cformat.yHeight = yHeight;   //  120, 180   Specifies the character height, in twips (1/1440 of an inch, or 1/20 of a printer's point). To use this member, set the CFM_SIZE flag in the dwMask member.
    m_cformat.crBackColor = crBackColor;



    //SCF_DEFAULT 0x0000
    //WPARAM IS 0, mean default text format
    return 0 != SendMessage( EM_SETCHARFORMAT, SCF_DEFAULT, ( LPARAM )&m_cformat );
}

bool QRichEdit::SetCharFormat( DWORD dwMask,  DWORD dwEffects, LONG yHeight, LPTSTR szFaceName,  COLORREF crTextColor ,  COLORREF crBackColor )
{
    //cf.dwMask = CFM_STRIKEOUT|CFM_BOLD;
    //cf.dwEffects = CFE_STRIKEOUT;

    m_cformat.cbSize = sizeof( CHARFORMAT2 );
    m_cformat.dwMask = dwMask ;
    m_cformat.crTextColor = crTextColor;
    m_cformat.dwEffects = dwEffects;
    _tcscpy_s( m_cformat.szFaceName, szFaceName );
    m_cformat.yHeight = yHeight; //120, 180   Specifies the character height, in twips (1/1440 of an inch, or 1/20 of a printer's point). To use this member, set the CFM_SIZE flag in the dwMask member.
    m_cformat.crBackColor = crBackColor;

    return toBool( ( BOOL )SendMessage( EM_SETCHARFORMAT, SCF_SELECTION, ( LPARAM )&m_cformat ) );
}


bool QRichEdit::SetTextColor( COLORREF crTextColor )
{
    m_cformat.cbSize = sizeof( CHARFORMAT2 );
    m_cformat.dwMask = CFM_COLOR ;
    m_cformat.crTextColor = crTextColor;

    return toBool( ( BOOL )SendMessage( EM_SETCHARFORMAT, SCF_SELECTION, ( LPARAM )&m_cformat ) );
}

bool QRichEdit::SetTextBackground( COLORREF  crBackColor )
{
    m_cformat.cbSize = sizeof( CHARFORMAT2 );
    m_cformat.dwMask = CFM_BACKCOLOR ;
    m_cformat.crBackColor = crBackColor;

    return toBool( ( BOOL )SendMessage( EM_SETCHARFORMAT, SCF_SELECTION, ( LPARAM )&m_cformat ) );
}

bool QRichEdit::SetTextFont( LPTSTR szFaceName )
{
    m_cformat.cbSize = sizeof( CHARFORMAT2 );
    m_cformat.dwMask = CFM_FACE ;
    _tcscpy_s( m_cformat.szFaceName, szFaceName );

    return toBool( ( BOOL )SendMessage( EM_SETCHARFORMAT, SCF_SELECTION, ( LPARAM )&m_cformat ) );
}

bool QRichEdit::SetTextFontSize( LONG yHeight )
{
    m_cformat.cbSize = sizeof( CHARFORMAT2 );
    m_cformat.dwMask = CFM_SIZE ;
    m_cformat.yHeight = yHeight;

    return toBool( ( BOOL )SendMessage( EM_SETCHARFORMAT, SCF_SELECTION, ( LPARAM )&m_cformat ) );
}

void QRichEdit::LimitText( WPARAM nChars )
{
    SendMessage( EM_LIMITTEXT, nChars, 0 );
}

void QRichEdit::LimitTextEx( LPARAM nChars )
{
    SendMessage( EM_EXLIMITTEXT, 0,  nChars );
}

void QRichEdit::SetOptions( WORD wOp, DWORD dwFlags )
{
    SendMessage( EM_SETOPTIONS, ( WPARAM )wOp, ( LPARAM )dwFlags );
}


DWORD QRichEdit::SetEventMask( DWORD dwEventMask )
{
    return ( DWORD )SendMessage( EM_SETEVENTMASK, 0, dwEventMask );
}



//DEFECT
QString QRichEdit::GetTextRange( int ncharrMin, int ncharrMax )
{
    //Set the CHARRANGE for the m_trange = the characters sent by ENLINK
    m_trange.chrg.cpMin = ncharrMin;
    m_trange.chrg.cpMax = ncharrMax;

    //Set the size of the character buffers, + 1 for null character
    int nLength = int( ( m_trange.chrg.cpMax - m_trange.chrg.cpMin + 1 ) );

    //create an ANSI buffer and a Unicode (Wide Character) buffer
    LPTSTR lpszChar = new TCHAR[nLength + 1];
    lpszChar[nLength] = _T( '\0' );

    //Set the m_trange LPWSTR character buffer = Unicode buffer
    m_trange.lpstrText = lpszChar;

    //Get the Unicode text
    SendMessage( EM_GETTEXTRANGE, 0,  ( LPARAM ) &m_trange );

    // Convert the Unicode RTF text to ANSI.
    //WideCharToMultiByte(CP_ACP, 0, lpszWChar, -1, m_lpszChar, nLength, nullptr, nullptr);

    //Release buffer memory

    QString s( lpszChar );
    delete [] lpszChar;



    return s;
}


DWORD CALLBACK QRichEdit::SetStreamCallback( DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, PLONG pcb )
{
    QFile * fis = ( QFile * )dwCookie;

    if (  fis->Read( lpBuff, cb, ( DWORD & )*pcb ) )
    {
        return 0;
    }

    return ( DWORD ) - 1;
}

DWORD CALLBACK QRichEdit::SetStreamCallbackBE( DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, PLONG pcb )
{
    QFile * fis = ( QFile * )dwCookie;

    if (  fis->Read( lpBuff, cb, ( DWORD & )*pcb ) )
    {
        for ( LONG i = 0; i < *pcb; i += 2 )
        {
            BYTE aux = lpBuff[i];
            lpBuff[i] = lpBuff[i + 1];
            lpBuff[i + 1] = aux;

        }

        return 0;
    }

    return ( DWORD ) - 1;
}
bool QRichEdit::LoadFile( QFile & fis, UINT sfMode )
{

    bool big_endian = false;

    //verificam boom
    //SF_UNICODE
    //big_endian = true;

    if ( ( sfMode & SF_TEXT ) == SF_TEXT )
    {
        //little
        //big endian
        //utf8 sau ansi

        byte BOM[4];
        fis.Read( BOM, 4 );

        if ( BOM[0] == 0xEF && BOM[1] == 0xBB && BOM[2] == 0xBF )
        {
            //utf8
            fis.Seek( 0, 0 );
        }
        else if ( ( BOM[0] == 0xFE ) && ( BOM[1] == 0xFF ) )
        {
            //utf16 big-endian
            big_endian = true;
            fis.Seek( 2, 0 );
            sfMode |= SF_UNICODE;

        }
        else if ( BOM[0] == 0xFF && BOM[1] == 0xFE )
        {
            //utf16 little-endian
            sfMode |= SF_UNICODE;
            fis.Seek( 0, 0 );
        }
        else
        {
            //ansii sau ceva fara bom
            //se poate face o analiza
            fis.Seek( 0, 0 );
        }

        //if ( BOM[0] == 0xFF && BOM[1] == 0xFE && BOM[2] == 0x00 && BOM[3] == 0x00 )
        //{
        //	//utf32 little-endian
        //
        //}

        //if ( BOM[0] == 0x00 && BOM[1] == 0x00 && BOM[2] == 0xFE && BOM[3] == 0xFF )
        //{
        //	//utf32 big-endian
        //
        //}


    }


    EDITSTREAM es = { 0 };
    es.pfnCallback = big_endian ? SetStreamCallbackBE : SetStreamCallback;
    es.dwCookie = reinterpret_cast<DWORD_PTR>( &fis );

    if ( SendMessage( EM_STREAMIN, sfMode, ( LPARAM )&es ) && es.dwError == 0 )
    {
        return true;
    }


    return false;
}




DWORD CALLBACK QRichEdit::GetStreamCallback( DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, PLONG pcb )
{
    QFile * fis = ( QFile * )dwCookie;

    if (  fis->Write( lpBuff, cb, ( DWORD & )*pcb ) )
    {
        return 0;
    }

    return ( DWORD ) - 1;
}
bool QRichEdit:: SaveFile( QFile & fis, UINT sfMode )
{

    EDITSTREAM es = { 0 };
    es.pfnCallback = GetStreamCallback;
    es.dwCookie = reinterpret_cast<DWORD_PTR>( &fis );

    if ( SendMessage( EM_STREAMOUT, sfMode, ( LPARAM )&es ) && es.dwError == 0 ) // (CP_UTF8 << 16) | SF_USECODEPAGE |
    {
        return true;
    }


    return false;
}



//public static Encoding GetFileEncoding(string srcFile)
//{
//	// *** Use Default of Encoding.Default (Ansi CodePage)
//	Encoding enc = Encoding.Default;
//
//	// *** Detect byte order mark if any - otherwise assume default
//	byte[] buffer = new byte[5];
//	FileStream file = new FileStream(srcFile, FileMode.Open);
//	file.Read(buffer, 0, 5);
//	file.Close();
//
//	if (buffer[0] == 0xef && buffer[1] == 0xbb && buffer[2] == 0xbf)
//		enc = Encoding.UTF8;
//	else if (buffer[0] == 0xfe && buffer[1] == 0xff)
//		enc = Encoding.Unicode;
//	else if (buffer[0] == 0 && buffer[1] == 0 && buffer[2] == 0xfe && buffer[3] == 0xff)
//		enc = Encoding.UTF32;
//	else if (buffer[0] == 0x2b && buffer[1] == 0x2f && buffer[2] == 0x76)
//		enc = Encoding.UTF7;
//	else if (buffer[0] == 0xFE && buffer[1] == 0xFF)
//		// 1201 unicodeFFFE Unicode (Big-Endian)
//		enc = Encoding.GetEncoding(1201);
//	else if (buffer[0] == 0xFF && buffer[1] == 0xFE)
//		// 1200 utf-16 Unicode
//		enc = Encoding.GetEncoding(1200);
//
//
//	return enc;
//}





DWORD CALLBACK QRichEdit::SetRTFCallback( DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, PLONG pcb )
{
    MYSTREAM * es =  ( MYSTREAM * )dwCookie;

    int sz = es->pbuff->GetSize();

    LONG cb2 = min ( sz - es->pos, cb );

    es->pbuff->CopyTo( lpBuff, es->pos, cb2 ) ;
    es->pos  += cb2;

    *pcb  = cb2;

    return ( cb == cb2 ) ? 0 : -1;
}

bool QRichEdit::SetRTF( QBuffer & s )
{

    MYSTREAM es;

    es.pfnCallback = SetRTFCallback;
    es.dwCookie = reinterpret_cast<DWORD_PTR>( &es );
    es.pos = 0;
    es.pbuff = &s;

    if ( SendMessage( EM_STREAMIN,   SF_RTF, ( LPARAM )&es ) && es.dwError == 0 )
    {

        return true;
    }

    return false;
}



DWORD CALLBACK QRichEdit::GetRTFCallback( DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, PLONG pcb )
{
    QBuffer  *  pb = ( QBuffer * )dwCookie;

    QBuffer s2(  lpBuff, cb );
    pb->Add( s2 );

    *pcb  = cb;
    return 0;
    //return (DWORD)-1;
}


bool QRichEdit::GetRTF( QBuffer & s )
{
    EDITSTREAM es = { 0 };
    es.pfnCallback = GetRTFCallback;
    es.dwCookie = reinterpret_cast<DWORD_PTR>( &s );

    if ( SendMessage( EM_STREAMOUT,   SF_RTF, ( LPARAM )&es ) && es.dwError == 0 )
    {
        return true;
    }

    return false;

}



bool QRichEdit::SetTextBold()
{
    m_cformat.dwMask = CFM_BOLD;
    m_cformat.dwEffects ^= CFE_BOLD;

    return toBool( ( BOOL )SendMessage( EM_SETCHARFORMAT, SCF_SELECTION, ( LPARAM )&m_cformat ) );
}

bool QRichEdit::SetTextItalic()
{
    m_cformat.dwMask = CFM_ITALIC;
    m_cformat.dwEffects ^= CFE_ITALIC;

    return toBool( ( BOOL )SendMessage( EM_SETCHARFORMAT, SCF_SELECTION, ( LPARAM )&m_cformat ) );
}
bool QRichEdit::SetTextUnderline( )
{
    m_cformat.dwMask = CFM_UNDERLINE;
    m_cformat.dwEffects ^= CFE_UNDERLINE;

    return toBool( ( BOOL )SendMessage( EM_SETCHARFORMAT, SCF_SELECTION, ( LPARAM )&m_cformat ) );
}



// by Costel
bool QRichEdit::InsertImage( HBITMAP bitmap )
{
    QImageIDataObject * img = new QImageIDataObject();
    img->SetBitmap( bitmap );


    IRichEditOle * pole = nullptr;
    bool bo = GetOleInterface(  &pole );


    IOleClientSite * pOCS = nullptr;
    pole->GetClientSite( &pOCS );


    LPLOCKBYTES pLB = 0;
    CreateILockBytesOnHGlobal( 0, TRUE, &pLB );

    IStorage * pStorage = nullptr;
    StgCreateDocfileOnILockBytes( pLB, STGM_SHARE_EXCLUSIVE | STGM_CREATE | STGM_READWRITE, 0, &pStorage );
    IOleObject * pOOb = img->GetOleObject( pOCS, pStorage );

    OleSetContainedObject( pOOb, TRUE );

    CLSID clsid;
    pOOb->GetUserClassID( &clsid );

    REOBJECT ro = { sizeof( REOBJECT ), REO_CP_SELECTION, clsid,  pOOb, pStorage, pOCS, {0, 0}, DVASPECT_CONTENT, REO_RESIZABLE, 0};
    pole->InsertObject( &ro );

    pOCS->Release();
    pStorage->Release();
    pLB->Release();
    pOOb->Release();

    //free
    delete img;

    return true;
}





////// RICHOLE ////////////////////////////////////////
//QDocument*				 g_pDoc = nullptr;
//LPOLEINPLACEACTIVEOBJECT g_pActiveObject = nullptr;
//QOleInPlaceFrame*		 g_pInPlaceFrame = nullptr;
//RECT					 g_rcBorderSpace;
//HMENU					 g_hmenuMain = nullptr;

//
//
//QDocument::QDocument()
//{
//    m_pszFileName = nullptr;
//    m_hwndFrame = nullptr;
//    m_hwndEdit = nullptr;
//    m_pInPlaceFrame = nullptr;
//    m_cStorages = 0;
//	m_pRichEditOle = nullptr;
//}
//
//QDocument::QDocument(HWND hwndFrame, HWND hwndEdit, QOleInPlaceFrame* pInPlaceFrame)
//        : m_hwndFrame(hwndFrame),
//          m_hwndEdit(hwndEdit),
//          m_pInPlaceFrame(pInPlaceFrame)
//{
//    m_pszFileName = nullptr;
//    m_cStorages = 0;
//	m_pRichEditOle = nullptr;
//}
//
//QDocument::~QDocument()
//{
//	//DebugTrace(TEXT("QDocument::~QDocument.\r\n"));
//    if (m_pszFileName)
//        delete [] m_pszFileName;
//
//    //
//    // We need to go through and deactivate and close any objects that are
//    // currently open or active in the rich edit control.  If any objects
//    // are left running they will remain in memory even after this program
//    // is long gone.
//    //
//	if (m_pRichEditOle)
//	{
//		HRESULT hr = 0;
//
//        //
//		// Start by getting the total number of objects in the control.
//        //
//		int objectCount = m_pRichEditOle->GetObjectCount();
//
//        //
//        // Loop through each object in the control and if active deactivate
//        // and if open, close.
//        //
//		for (int i = 0; i < objectCount; i++)
//		{
//			REOBJECT reObj;
//		    ZeroMemory(&reObj, sizeof(REOBJECT));
//			reObj.cbStruct  = sizeof(REOBJECT);
//
//            //
//			// Get the Nth object
//            //
//			hr = m_pRichEditOle->GetObject(i,&reObj,REO_GETOBJ_POLEOBJ);
//			if(SUCCEEDED(hr))
//			{
//                //
//                // If active, deactivate.
//                //
//				if (reObj.dwFlags && REO_INPLACEACTIVE)
//					m_pRichEditOle->InPlaceDeactivate();
//
//                //
//				// If the object is open, close it.
//                //
//				if(reObj.dwFlags  &&  REO_OPEN)
//					hr = reObj.poleobj->Close(OLECLOSE_NOSAVE);
//
//		   		reObj.poleobj->Release();
//			}
//		}
//		m_pRichEditOle->Release();
//	}
//
//    if (m_pRECallback)
//        m_pRECallback->Release();
//}
//
//
///////////////////////////////////////////////////////////////////////////////
////
//// Initialization
////
//
////
////  FUNCTION:   QDocument::Initialize
////
////  PURPOSE:    Performs any initialization for the QDocument object that
////				can fail.  This includes creating the IRichEditOleCallback
////				interface and associating it with the edit control.
////
////  RETURN VALUE:
////      Returns TRUE if all the initialization was successful, or FALSE
////		otherwise.
////
//
//BOOL QDocument::Initialize(void)
//{
//    // TODO: Perform any initialization that can fail here.
//
//    //
//    // Instantiate the QOleCallback object and tell the
//    // edit control to use it.
//    //
//
//
//	 m_pRECallback = new QOleCallback(  m_hwndEdit);
//    //if (!m_pRECallback)
//    //{
//    //    return (FALSE);
//    //}
//    m_pRECallback->AddRef();
//
//   SendMessage(m_hwndEdit, EM_SETOLECALLBACK, 0, (LPARAM)m_pRECallback);
//
//
//
//    //
//    // Get the IRichEditOle interface from the edit control.
//    //
//    SendMessage(m_hwndEdit, EM_GETOLEINTERFACE, 0,
//                (LPARAM) (LPVOID*) &m_pRichEditOle);
//
//    //
//	// Some applications fail to insert if the hostname is not set (for
//    // example, MS Word) so this is essential to be done.
//    //
//	//if (m_pRichEditOle)
// //   {
//	//	if (m_pszFileName)
//	//		m_pRichEditOle->SetHostNames(g_szAppName, m_pszFileName);
//	//	else
//	//		m_pRichEditOle->SetHostNames(g_szAppName, TEXT("Untitled"));
// //   }
//
//    //
//    // While we're at it empty the contents of the edit control.
//    //
//    SendMessage(m_hwndEdit, WM_SETTEXT, 0, (LPARAM)(LPTSTR) TEXT(""));
//
//    return (TRUE);
//}
//
//
///////////////////////////////////////////////////////////////////////////////
////
//// File I/O
////
//
////
////  FUNCTION:   QDocument::Open
////
////  PURPOSE:    Handles opening a file and loading it into the Edit Control.
////
////  RETURN VALUE:
////      Returns TRUE if the read was successful, or FALSE otherwise.
////
//
//BOOL QDocument::Open(void)
//{
//	//DebugTrace(TEXT("QDocument::Open.\r\n"));
//
//    //
//    // Start by displaying the common dialog to get the file name to load.
//    //
//    TCHAR szFile[MAX_PATH];
//
//
//	/*if (!GetOpenSaveFileName(m_hwndFrame, TRUE, szFile, sizeof(szFile)))
//    {
//        return (FALSE);
//    }*/
//
//    //
//    // Save the file name.
//    //
//    if (m_pszFileName)
//        delete [] m_pszFileName;
//
//    m_pszFileName = new TCHAR[lstrlen(szFile) + 1];
//    lstrcpy(m_pszFileName, szFile);
//
//    //
//	// update the HostName with the New FileName
//    //
//	if (m_pRichEditOle)
//		m_pRichEditOle->SetHostNames("alex1" /*g_szAppName*/, "alex2"/*m_pszFileName*/);
//
//    //
//    // Open a the file using the file name specified.
//    //
//    HANDLE hf = CreateFile(m_pszFileName, GENERIC_READ | GENERIC_WRITE,
//                           FILE_SHARE_READ, nullptr, OPEN_EXISTING,
//                           FILE_ATTRIBUTE_NORMAL, 0);
//    if (!hf)
//    {
//        //ErrorHandler();
//        return (FALSE);
//    }
//
//    //
//    // Have the RichEdit control stream it's contents from this stream.
//    //
//    EDITSTREAM es;
//    es.dwCookie = (DWORD) hf;
//    es.dwError = 0;
//    es.pfnCallback = EditStreamIn;
//
//    SendMessage(m_hwndEdit, EM_STREAMIN, SF_RTF,
//                (LPARAM)(EDITSTREAM*) &es);
//
//    CloseHandle(hf);
//
//    return (TRUE);
//}
//
//
////
////  FUNCTION:   QDocument::Save
////
////  PURPOSE:    Saves the contents of the edit control to disk.
////
////  PARAMETERS:
////      fSaveAs - TRUE if the user want's to change the name, or FALSE to save
////				  in the current file.
////
////  RETURN VALUE:
////      Returns TRUE if the file was saved OK, or FALSE otherwise.
////
//
//BOOL QDocument::Save(BOOL fSaveAs)
//{
//    //
//    // If either fSaveAs is TRUE or m_pszFileName is nullptr, we need to ask
//    // the user for a file name.
//    //
//    if (nullptr == m_pszFileName || fSaveAs)
//    {
//        m_pszFileName = new TCHAR[MAX_PATH];
//       /* if (!GetOpenSaveFileName(m_hwndFrame, FALSE, m_pszFileName, MAX_PATH))
//        {
//            delete [] m_pszFileName;
//            m_pszFileName = nullptr;
//            return (FALSE);
//        }*/
//    }
//
//    //
//	// Update the HostName with the New FileName.
//    //
//	if (m_pRichEditOle)
//		m_pRichEditOle->SetHostNames("alex1" /*g_szAppName*/, "alex2"/*m_pszFileName*/);
//
//    HANDLE hf = CreateFile(m_pszFileName, GENERIC_READ | GENERIC_WRITE,
//                           FILE_SHARE_READ, nullptr, CREATE_ALWAYS,
//                           FILE_ATTRIBUTE_NORMAL, nullptr);
//    if (!hf)
//    {
//        //ErrorHandler();
//        return (FALSE);
//    }
//
//    //
//    // Now have the RichEdit control stream it's contents into this stream.
//    //
//    EDITSTREAM es;
//    es.dwCookie = (DWORD) hf;
//    es.dwError = 0;
//    es.pfnCallback = EditStreamOut;
//
//    SendMessage(m_hwndEdit, EM_STREAMOUT, SF_RTF, (LPARAM)(EDITSTREAM*) &es);
//
//    CloseHandle(hf);
//
//    return (TRUE);
//}
//
//
////
////  FUNCTION:   QDocument::EditStreamOut
////
////  PURPOSE:    This function is called repetitvely as the RichEdit control is
////				writing it's contents out to file.  The function writes all
////				the information to the HFILE located in dwCookie.
////
////  PARAMETERS:
////      dwCookie - Contains an HFILE that the data should be written to.
////		pbBuff   - Pointer to the buffer that should be written to the disk.
////		cb		 - Number of the bytes contained in pbBuff that should be
////				   written.
////		pcb 	 - Points to where the function should return the number of
////				   bytes actually written to disk.
////
////  RETURN VALUE:
////      Returns zero always.
////
//
//DWORD CALLBACK QDocument::EditStreamOut(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG FAR *pcb)
//{
//	//DebugTrace(TEXT("QDocument::EditStreamOut.\r\n"));
//
//    WriteFile((HANDLE) dwCookie, pbBuff, cb, (ULONG*) pcb, nullptr);
//    return (0);
//}
//
//
////
////  FUNCTION:   QDocument::EditStreamIn
////
////  PURPOSE:    This function is called repetitvely as the RichEdit control is
////				reading it's contents from the file.  The function reads the
////				data from the HFILE located in dwCookie.
////
////  PARAMETERS:
////      dwCookie - Contains an HFILE that the data should be written to.
////		pbBuff   - Pointer to the buffer that should be filled with the data.
////		cb		 - Number of the bytes contained in pbBuff that should be
////				   read.
////		pcb 	 - Points to where the function should return the number of
////				   bytes actually read from the disk.
////
////  RETURN VALUE:
////      Returns zero always.
////
//
//DWORD CALLBACK QDocument::EditStreamIn(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG FAR *pcb)
//{
//	//DebugTrace(TEXT("QDocument::EditStreamIn.\r\n"));
//    ReadFile((HANDLE)dwCookie, pbBuff, cb, (ULONG*) pcb, nullptr);
//    return (0);
//}
//
//
////
////  FUNCTION:   QDocument::GetNewStorage
////
////  PURPOSE:    Retrieves a new storage within the document's storage.
////
////  PARAMETERS:
////      ppStg - Pointer to an IStorage interface where the fucntion should
////              return the new storage.
////
////  RETURN VALUE:
////      Returns an HRESULT signfiying success or failure.
////
//
//HRESULT QDocument::GetNewStorage(LPSTORAGE* ppStg)
//{
//	//DebugTrace(TEXT("QDocument::GetNewStorage.\r\n"));
//
//    if (!ppStg)
//        return E_INVALIDARG;
//
//    *ppStg = nullptr;
//
//    //
//    // We need to create a new storage for an object to occupy.  We're going
//    // to do this the easy way and just create a storage on an HGLOBAL and let
//    // OLE do the management.  When it comes to saving things we'll just let
//    // the RichEdit control do the work.  Keep in mind this is not efficient,
//    // but this program is just for demonstration.
//    //
//
//    LPLOCKBYTES pLockBytes;
//    HRESULT hr = CreateILockBytesOnHGlobal(nullptr, TRUE, &pLockBytes);
//    if (FAILED(hr))
//        return hr;
//
//    hr = StgCreateDocfileOnILockBytes(pLockBytes,
//                                      STGM_SHARE_EXCLUSIVE | STGM_CREATE |
//                                          STGM_READWRITE,
//                                      0,
//                                      ppStg);
//    pLockBytes->Release();
//    return (hr);
//}
//
//
////
////  FUNCTION:   QDocument::InsertObject
////
////  PURPOSE:    Allows the user to create a new OLE object in the RichEdit
////              control via the InsertObject() common dialog.
////
////  RETURN VALUE:
////      Returns TRUE if the object was inserted successfully, or FALSE
////      otherwise.
////
//
//BOOL QDocument::InsertObject(void)
//{
//    BOOL fSuccess = FALSE;
//	LPOLEOBJECT pOleObject = nullptr;
////
////	//DebugTrace(TEXT("QDocument::InsertObject.\r\n"));
////
////    //
////    // Double check that we have what we need before we start.
////    //
////    if (!m_hwndEdit || !m_pRECallback)  return (FALSE);
////
////    //
////    // Get a client site from the RichEdit control.
////    //
////    LPOLECLIENTSITE pOleSite;
////    if (FAILED(m_pRichEditOle->GetClientSite(&pOleSite)))
////    {
////        //DisplayMessage(m_hwndFrame, IDS_ERR_NOCLIENTSITE);
////        goto error;
////    }
////
////    //
////    // Get a new substorage for the new object.
////    //
////    LPSTORAGE pStgItem;
////    if (FAILED(GetNewStorage(&pStgItem)))
////    {
////        //DisplayMessage(m_hwndFrame, IDS_ERR_CANTCREATESTG);
////        goto error;
////    }
////
////    //
////    // Display the InsertObject dialog
////    //
////    TCHAR szBuffer[MAX_PATH];
////    OLEUIINSERTOBJECT io;
////
////    ZeroMemory(&io, sizeof(OLEUIINSERTOBJECT));
////    szBuffer[0] = 0;
////
////    io.cbStruct         = sizeof(OLEUIINSERTOBJECT);
////    io.dwFlags          = IOF_SHOWHELP | IOF_CREATENEWOBJECT |
////                          IOF_CREATEFILEOBJECT | IOF_SELECTCREATENEW |
////                          IOF_CREATELINKOBJECT;
////    io.hWndOwner        = m_hwndFrame;
////    io.lpszFile         = szBuffer;
////    io.cchFile          = sizeof(szBuffer);
////    io.iid              = IID_IOleObject;
////    io.oleRender        = OLERENDER_DRAW;
////    io.lpIOleClientSite = pOleSite;
////    io.lpIStorage       = pStgItem;
////    io.ppvObj           = (LPVOID*) &pOleObject;
////    io.clsid            = CLSID_NULL;
////
////    DWORD dwReturn;
////    if (OLEUI_SUCCESS != (dwReturn = OleUIInsertObject(&io)))
////    {
////        //
////        // The dialog failed for some reason.  Let's give the user
////        // something informative and exit.
////        //
////        TCHAR szBuffer2[MAX_PATH];
////
////        if (dwReturn == OLEUI_CANCEL)
////            goto error;
////        else if (dwReturn == OLEUI_IOERR_SCODEHASERROR)
////        {
////            LoadString(g_hInstance, IDS_ERR_SCODEHASERROR, szBuffer2, sizeof(szBuffer2));
////            wsprintf(szBuffer, szBuffer2, io.sc);
////        }
////        else
////        {
////            LoadString(g_hInstance, IDS_ERR_INSERTOBJECT, szBuffer,
////                       sizeof(szBuffer));
////        }
////
////        MessageBox(m_hwndFrame, szBuffer, g_szAppName,
////                   MB_ICONEXCLAMATION | MB_OK);
////        goto error;
////    }
////
////    //
////    // We got the object from the InsertObject dialog ok.  Now let's
////    // tell the RichEdit control about it.
////    //
////	pOleObject = (LPOLEOBJECT)*io.ppvObj;
////
////    REOBJECT reObj;
////    ZeroMemory(&reObj, sizeof(REOBJECT));
////    reObj.cbStruct  = sizeof(REOBJECT);
////    reObj.cp        = REO_CP_SELECTION;
////	reObj.clsid		= io.clsid;
////    reObj.poleobj   = pOleObject;
////    reObj.pstg      = pStgItem;
////    reObj.polesite  = pOleSite;
////    reObj.sizel.cx  = 0;
////    reObj.sizel.cy  = 0;
////    reObj.dvaspect  = DVASPECT_CONTENT;
////    reObj.dwFlags   = REO_RESIZABLE;
////    reObj.dwUser    = 0;
////
////    if (io.dwFlags & IOF_SELECTCREATENEW)
////        reObj.dwFlags |= REO_BLANK;
////
////    //
////    // The RichEdit control doesn't setup advises if reObj.clsid == CLSID_NULL.
////    // Try our darnedest to get a CLSID.
////    //
////    if (IsEqualCLSID(reObj.clsid, CLSID_NULL))
////    {
////#ifdef UNICODE
////        if (FAILED(GetClassFile(szBuffer, &reObj.clsid)))
////#else
////        WCHAR wszFile[MAX_PATH];
////        MultiByteToWideChar(CP_ACP, 0, szBuffer, -1, wszFile, sizeof(wszFile));
////
////        if (FAILED(GetClassFile(wszFile, &reObj.clsid)))
////#endif
////            DebugMsg(TEXT("No CLSID, but continuing on...\r\n"));
////    }
////
////    //
////    // Do we want an iconized version?
////    //
////    if (io.dwFlags & IOF_CHECKDISPLAYASICON)
////    {
////        BOOL fUpdate;
////
////        if (OleStdSwitchDisplayAspect(pOleObject,
////                                      &reObj.dvaspect,
////                                      DVASPECT_ICON,
////                                      io.hMetaPict,
////                                      TRUE,
////                                      FALSE,
////                                      nullptr,
////                                      &fUpdate))
////        {
////            //DisplayMessage(m_hwndFrame, IDS_ERR_CANTDISPLAYICON);
////        }
////    }
//////	SendMessage(m_hwndFrame, WM_SETREDRAW, FALSE,0);
////    //
////    // Insert the object into the edit control.
////    //
////    if (FAILED(m_pRichEditOle->InsertObject(&reObj)))
////    {
////        //DisplayMessage(m_hwndFrame, IDS_ERR_CANTINSERTOBJECT);
////        goto error;
////    }
////
////   fSuccess = TRUE;
////
////    //
////    // Do the "Show" verb only on new objects.
////    //
////    if (io.dwFlags & IOF_SELECTCREATENEW)
////    {
////        //
////        // Get the object's position.
////        //
////        POINT pt;
////        SendMessage(m_hwndEdit, EM_POSFROMCHAR, (WPARAM) &pt,
////                    REO_IOB_SELECTION);
////
////        RECT rect = {0, 0, 100, 100};
////        OffsetRect(&rect, pt.x, pt.y);
////
////        pOleObject->DoVerb(OLEIVERB_SHOW, nullptr, pOleSite, 0, m_hwndEdit, &rect);
////    }
//////SendMessage(m_hwndFrame, WM_SETREDRAW, TRUE,0);
//////RedrawWindow(m_hwndFrame,nullptr,nullptr,RDW_ERASE|RDW_ALLCHILDREN|RDW_UPDATENOW);
////error:
////    if (io.hMetaPict)
////        OleUIMetafilePictIconFree(io.hMetaPict);
////
////    if (pOleSite)
////        pOleSite->Release();
////
////    if (pStgItem)
////        pStgItem->Release();
////
////    if (pOleObject)
////        pOleObject->Release();
//
//    return fSuccess;
//}
//
//
////
////  FUNCTION:   QDocument::DoVerb
////
////  PURPOSE:    Handles figuring out which object currently is selected
////				and sending a verb to that object.
////
////  PARAMETERS:
////      (in) id - Identifier of the Verb to tell the object to execute.
////
////  RETURN VALUE:
////      Returns an HRESULT indicating success or failure.
////
//
//HRESULT QDocument::DoVerb(UINT id)
//{
//	//DebugTrace(TEXT("QDocument::DoVerb.\r\n"));
//
//	//
//	// Figure out which object is selected.
//	//
//	CHARRANGE cr;
//	SendMessage(m_hwndEdit, EM_EXGETSEL, 0, (LPARAM)(CHARRANGE*) &cr);
//
//	//
//	// Get the object and client site pointers from the control.
//	//
//	REOBJECT reObj;
//	ZeroMemory(&reObj, sizeof(REOBJECT));
//	reObj.cbStruct = sizeof(REOBJECT);
//	reObj.cp = cr.cpMin;
//
//	HRESULT hr = m_pRichEditOle->GetObject(REO_IOB_USE_CP, &reObj,
//										   REO_GETOBJ_POLEOBJ |
//										   REO_GETOBJ_POLESITE);
//	if (FAILED(hr))
//		return (hr);
//
//	//
//	// At this point REOBJECT.poleobj should have the IOleObject interface we
//	// need and REOBJECT.polesite should have the IOleClientSite interface we
//	// need.  We still need to create a rectangle out of the object's site.
//	//
//	POINT pt;
//	RECT rc;
//	memset((LPVOID)&rc,0,sizeof(rc));
//	SendMessage(m_hwndEdit, EM_POSFROMCHAR, (WPARAM)&pt, cr.cpMin);
//
//    //
//    // Need to convert from HIMETRIC to screen pixels.  GetDC(nullptr) will get
//    // the HDC for the entire screen.
//    //
//	HDC hdc = GetDC(nullptr);
//    rc.right  = MulDiv(reObj.sizel.cx, GetDeviceCaps(hdc, LOGPIXELSX), 2540);
//    rc.bottom = MulDiv(reObj.sizel.cy, GetDeviceCaps(hdc, LOGPIXELSY), 2540);
//    ReleaseDC(nullptr, hdc);
//    OffsetRect(&rc, pt.x, pt.y);
//
//    hr = reObj.poleobj->DoVerb(id, nullptr, reObj.polesite, 0, m_hwndEdit, &rc);
//
// 	reObj.poleobj->Release();
//	reObj.polesite->Release();
//
//	return (hr);
//}
//
//
////
////  FUNCTION:   QDocument::MoveEditControl
////
////  PURPOSE:    Handles updating the position of the RichEdit control within
////				the frame window.
////
////  PARAMETERS:
////      (in) left, top - Position of the new upper left corner of the edit
////						 control in client coordinates based on the frame wnd.
////		(in) width, height - New width and height of the control.
////
////  RETURN VALUE:
////      Returns TRUE if the move was successful, or FALSE otherwise.
////
//
//BOOL QDocument::MoveEditControl(int left, int top, int width, int height,
//                                int style)
//{
//    return SetWindowPos(m_hwndEdit, 0, left, top, width, height, style);
//}








///////////////////////////////////////////////////////////////////////////////////////////////

//extern QDocument* g_pDoc;



QOleInPlaceFrame::~QOleInPlaceFrame()
{

}


/////////////////////////////////////////////////////////////////////////////
// IUnknown Interface members
//

HRESULT QOleInPlaceFrame::QueryInterface( REFIID riid, LPVOID * ppv )
{
    *ppv = nullptr;

    //DebugTrace(TEXT("QOleInPlaceFrame::QueryInterface() returns "));

    if ( IID_IUnknown == riid )
    {
        //DebugTrace(TEXT("IUnknown.\r\n"));
        *ppv = ( LPUNKNOWN ) this;
    }
    else if ( IID_IOleWindow == riid )
    {
        //DebugTrace(TEXT("IOleWindow.\r\n"));
        *ppv = ( LPOLEWINDOW ) this;
    }
    else if ( IID_IOleInPlaceUIWindow == riid )
    {
        //DebugTrace(TEXT("IOleInPlaceUIWindow.\r\n"));
        *ppv = ( LPOLEINPLACEUIWINDOW ) this;
    }
    else if ( IID_IOleInPlaceFrame == riid )
    {
        //DebugTrace(TEXT("IOleInPlaceFrame.\r\n"));
        *ppv = ( LPOLEINPLACEFRAME ) this;
    }


    if ( nullptr == *ppv )
        return ResultFromScode( E_NOINTERFACE );

    ( ( LPUNKNOWN ) *ppv )->AddRef();
    return NOERROR;
}

ULONG QOleInPlaceFrame::AddRef()
{
    m_cRef++;
    //DebugCount(TEXT("QOleInPlaceFrame::AddRef().  Count = %d.\r\n"),  m_cRef);
    return m_cRef;
}

ULONG QOleInPlaceFrame::Release()
{
    m_cRef--;
    ///DebugCount(TEXT("QOleInPlaceFrame::Release().  Count = %d.\r\n"), m_cRef);

    if ( ! m_cRef )	delete this;

    return m_cRef;
}



/////////////////////////////////////////////////////////////////////////////
// IOleWindow Interface members
//

//
//  FUNCTION:   QOleInPlaceFrame::GetWindow
//
//  PURPOSE:    Returns the window handle of the top level application window.
//
//  PARAMETERS:
//      (out) pHwnd - Pointer where we return the handle of the frame window.
//
//  RETURN VALUE:
//      Returns an HRESULT signifying success or failure.
//

HRESULT QOleInPlaceFrame::GetWindow( HWND * pHwnd )
{
    //DebugTrace(TEXT("QOleInPlaceFrame::GetWindow.\r\n"));
    if ( !pHwnd )
        return E_INVALIDARG;

    *pHwnd = m_hwndFrame;
    return S_OK;
}


//
//  FUNCTION:   QOleInPlaceFrame::ContextSensitiveHelp
//
//  PURPOSE:    Notifies the frame that the object has entered context help
//				mode.
//
//  PARAMETERS:
//      (in)  fEnterMode - TRUE if the object is entering help mode, FALSE if
//					 	   leaving help mode.
//
//  RETURN VALUE:
//      Returns an HRESULT signifying success or failure.
//

HRESULT QOleInPlaceFrame::ContextSensitiveHelp( BOOL fEnterMode )
{
    //DebugTrace(TEXT("QOleInPlaceFrame::ContextSensitiveHelp.\r\n"));
    if ( m_fHelpMode != fEnterMode )
    {
        m_fHelpMode = fEnterMode;

        //
        // We're just going to forward the context sensitive help stuff
        // to the inplace active object since we don't support context
        // help ourselves.
        //



        ///*if (g_pActiveObject)
        //{
        //	LPOLEINPLACEOBJECT pInPlaceObject;
        //	g_pActiveObject->QueryInterface(IID_IOleInPlaceObject, (LPVOID*) &pInPlaceObject);
        //	if (pInPlaceObject)
        //	{
        //		pInPlaceObject->ContextSensitiveHelp(fEnterMode);
        //		pInPlaceObject->Release();
        //	}
        //}*/
    }

    return S_OK;
}


/////////////////////////////////////////////////////////////////////////////
// IOleInPlaceUIWindow Interface members
//

//
//  FUNCTION:   QOleInPlaceFrame::GetBorder
//
//  PURPOSE:    The object is asking for a rectangle in which it can put
//				toolbars and similar controls while active in place.
//
//  PARAMETERS:
//      (out) prcBorder - Pointer to a rectangle containing the area that the
//						  object can use.
//
//  RETURN VALUE:
//      Returns an HRESULT signifying success or failure.
//

HRESULT QOleInPlaceFrame::GetBorder( LPRECT prcBorder )
{
    //DebugTrace(TEXT("QOleInPlaceFrame::GetBorder.\r\n"));
    if ( !prcBorder )
        return E_INVALIDARG;

    //
    // Get the client area of the frame window.  We need to subtract the
    // area occupied by any toolbars or status bars we want to keep while
    // the object is active.
    //

    GetClientRect( m_hwndFrame, prcBorder );

    ///prcBorder->bottom -= g_pStatusBar->GetHeight();

    return S_OK;
}


//
//  FUNCTION:   QOleInPlaceFrame::RequestBorderSpace
//
//  PURPOSE:    Determines whether tools can be installed around the objects
//				window frame while the object is active in place.
//
//  PARAMETERS:
//      (in) pbw - Requested border space
//
//  RETURN VALUE:
//      Returns an HRESULT signifying success or failure.
//

HRESULT QOleInPlaceFrame::RequestBorderSpace( LPCBORDERWIDTHS pbw )
{
    //DebugTrace(TEXT("QOleInPlaceFrame::RequestBorderSpace.\r\n"));
    // Accept all requests
    return S_OK;
}


//
//  FUNCTION:   QOleInPlaceFrame::SetBorderSpace
//
//  PURPOSE:    Allocates space for the border requested by the active
//				in place object.
//
//  PARAMETERS:
//      (in) pbw - Pointer to the structure containing the requested widths
//				   in pixels of the tools.
//
//  RETURN VALUE:
//      Returns an HRESULT signifying success or failure.
//
//  COMMENTS:
//		If the pbw is nullptr, then the object is saying it doesn't have any of
//		it's own tools and we can leave our tools visible.  If pbw =
//		{0, 0, 0, 0), then the object has no tools, but it doesn't want our
//		tools visible either.
//


#define IDC_EDIT666  12345


HRESULT QOleInPlaceFrame::SetBorderSpace( LPCBORDERWIDTHS pbw )
{
    RECT rcClient;			// Rectangle of the current frame client area
    RECT rcOldEdit;			// Old rectangle for the edit control
    //DebugTrace(TEXT("QOleInPlaceFrame::SetBorderSpace.\r\n"));

    //
    // Remember the previous position of the client window in coordinates
    // relative to the frame window.
    //

    GetWindowRect( GetDlgItem( m_hwndFrame, IDC_EDIT666 ), &rcOldEdit );
    MapWindowPoints( nullptr, m_hwndFrame, ( LPPOINT ) &rcOldEdit, 2 );

    //
    // Get the client window rect.  We also need to subtract the area of any
    // status bars or tools that shouldn't disappear when the object is
    // active.
    //
    GetClientRect( m_hwndFrame, &rcClient );
    ///rcClient.bottom -= g_pStatusBar->GetHeight();

    if ( pbw )
    {
        //
        // Set the space for the object tools.
        //
        rcClient.left 	+= pbw->left;
        rcClient.top 	+= pbw->top;
        rcClient.right  -= pbw->right;
        rcClient.bottom -= pbw->bottom;

        //
        // Save the new border widths.  We also need to add space for any
        // status bars or tools that are still visible.
        //


        ///CopyRect(&g_rcBorderSpace, pbw);
    }
    else
    {
        //
        // No tools, reset the border space.  If we have any of our own tools
        // such as a status bar we need to add it to this rect.
        //

        ///SetRect(&g_rcBorderSpace, 0, 0, 0, 0);
    }

    //
    // Only move the window if the rectangles have changed.
    //
    if ( memcmp( &rcClient, &rcOldEdit, sizeof( RECT ) ) )
    {
        /*g_pDoc->MoveEditControl(rcClient.left,
                                rcClient.top,
                                rcClient.right - rcClient.left,
        	                    rcClient.bottom - rcClient.top,
                                SWP_NOZORDER | SWP_NOACTIVATE);
        */

        //DebugTrace(TEXT("Move Window in SetBorderSpace.\r\n"));
    }

    return S_OK;
}


//
//  FUNCTION:   QOleInPlaceFrame::SetActiveObject
//
//  PURPOSE:	Called by the object to provide the frame window a direct
// 				channel of communication with the active in-place object.
//
//  PARAMETERS:
//      (in) pInPlaceActiveObject - New active object, or nullptr if none.
//		(in) szObjName            - Name of the new active object.
//
//  RETURN VALUE:
//      Returns an HRESULT signifying success or failure.
//

HRESULT QOleInPlaceFrame::SetActiveObject( LPOLEINPLACEACTIVEOBJECT pInPlaceActiveObject, LPCOLESTR szObjName )
{

    //DebugTrace(TEXT("QOleInPlaceFrame::SetActiveObject.\r\n"));

    //
    // If object we have is same as the object passed then return S_OK.
    //

    ///if (pInPlaceActiveObject == g_pActiveObject) return S_OK;

    //
    // If we already have an active object, free that first.
    //

    ///if (g_pActiveObject) 		g_pActiveObject->Release();

    //
    // If we're given an object, AddRef it, and also update our global
    // pointer as well.
    //

    ///if (pInPlaceActiveObject) 		pInPlaceActiveObject->AddRef();

    ///g_pActiveObject = pInPlaceActiveObject;

    return S_OK;
}


/////////////////////////////////////////////////////////////////////////////
// IOleInPlaceFrame Interface members
//

//
//  FUNCTION:   QOleInPlaceFrame::InsertMenus
//
//  PURPOSE:    Called by the object server to allow the container to insert
//				its menu groups in the composite menu that will be used
//				during the in-place session.
//
//  PARAMETERS:
//      (in) hmenuShared      - Specifies a handle to an empty menu.
//		(in, out) pMenuWidths - Pointers to an array of six LONG values.  The
//								container fills elemts 0, 2, and 4 to reflect
//								the number of menu elements it provies in the
//								File, View, and Window menu groups.
//
//  RETURN VALUE:
//      Returns an HRESULT signifying success or failure.
//

HRESULT QOleInPlaceFrame::InsertMenus( HMENU hmenuShared,
                                       LPOLEMENUGROUPWIDTHS pMenuWidths )
{
    //DebugTrace(TEXT("QOleInPlaceFrame::InsertMenus.\r\n"));
    if ( !hmenuShared || !pMenuWidths )
        return E_INVALIDARG;

    ///TCHAR szMenuString[64];

    //
    // Add the file menu
    //


    ///GetMenuString(g_hmenuMain, 0, szMenuString, sizeof(szMenuString), MF_BYPOSITION);

    ///AppendMenu(hmenuShared, MF_POPUP, (UINT) GetSubMenu(g_hmenuMain, 0), szMenuString);
    pMenuWidths->width[0] = 1;

    //
    // Don't want to add the view menu.
    //
    pMenuWidths->width[2] = 0;

    //
    // Don't have a window menu either.
    //
    pMenuWidths->width[4] = 0;

    return S_OK;
}


//
//  FUNCTION:   QOleInPlaceFrame::SetMenu
//
//  PURPOSE:    Installs the composite menu into the window frame containing
//				the object that is being activated in place.
//
//  PARAMETERS:
//      (in) hmenuShared 	  - Handle to the composite menu.
//		(in) holemenu 		  - Handle to the menu descriptor.
//		(in) hwndActiveObject - Handle to the object's active window.
//
//  RETURN VALUE:
//      Returns an HRESULT signifying success or failure.
//

HRESULT QOleInPlaceFrame::SetMenu( HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject )
{
    //DebugTrace(TEXT("QOleInPlaceFrame::SetMenus.\r\n"));

    ///::SetMenu(m_hwndFrame, (holemenu ? hmenuShared : g_hmenuMain));
    ///DrawMenuBar(m_hwndFrame);

    //
    // Pass the menu descriptor to OLE.
    //


    return S_OK;  ///OleSetMenuDescriptor(holemenu, m_hwndFrame, hwndActiveObject, (LPOLEINPLACEFRAME) this, g_pActiveObject);
}


//
//  FUNCTION:   QOleInPlaceFrame::RemoveMenus
//
//  PURPOSE:    Called by the object server to give the container a chance
//				to remove it's menu elements from the in-place composite menu.
//
//  PARAMETERS:
//      (in) hmenuShared - Handle to the composite menu.
//
//  RETURN VALUE:
//      Returns an HRESULT signifying success or failure.
//

HRESULT QOleInPlaceFrame::RemoveMenus( HMENU hmenuShared )
{
    //DebugTrace(TEXT("QOleInPlaceFrame::RemoveMenus.\r\n"));
    if ( !hmenuShared )
        return E_INVALIDARG;

    int nResult;

    while ( ( nResult = GetMenuItemCount( hmenuShared ) ) && ( nResult != -1 ) )
        RemoveMenu( hmenuShared, 0, MF_BYPOSITION );

    return S_OK;
}


//
//  FUNCTION:   QOleInPlaceFrame::SetStatusText
//
//  PURPOSE:	Sets and displays status text about the in-place object in
//				the containers frame window status bar.
//
//  PARAMETERS:
//      (in) szStatusText -	String containing the message to display.
//
//  RETURN VALUE:
//      Returns an HRESULT signifying success or failure.
//

HRESULT QOleInPlaceFrame::SetStatusText( LPCOLESTR szStatusText )
{
    //DebugTrace(TEXT("QOleInPlaceFrame::SetStatusText.\r\n"));

    //
    // This string is sent to us in Unicode.  We need to decide if we should
    // translate it first.
    //
#ifndef UNICODE
    UINT cch = lstrlenW( szStatusText ) + 1;
    LPSTR pszMessage = new char[cch];

    ZeroMemory( pszMessage, cch );

    WideCharToMultiByte( CP_ACP, 0, szStatusText, -1, pszMessage,
                         cch, nullptr, nullptr );
    ///g_pStatusBar->ShowMessage(pszMessage);

    delete [] pszMessage;
#else
    ///g_pStatusBar->ShowMessage(szStatusText);
#endif

    return S_OK;
}


//
//  FUNCTION:   QOleInPlaceFrame::EnableModeless
//
//  PURPOSE:    Enables or disables modeless dialogs that are owned by the
//				frame window.
//
//  PARAMETERS:
//      fEnable - TRUE if the dialogs should be enabled, or FALSE to disable.
//
//  RETURN VALUE:
//      Returns an HRESULT signifying success or failure.
//

HRESULT QOleInPlaceFrame::EnableModeless( BOOL fEnable )
{
    //DebugTrace(TEXT("QOleInPlaceFrame::EnableModeless.\r\n"));

    //
    // We don't have any modeless dialogs.
    //
    return S_OK;
}


//
//  FUNCTION:   QOleInPlaceFrame::TranslateAccelerator
//
//  PURPOSE:    Translates keystrokes intended for the container frame while
//				an object is active in place.
//
//  PARAMETERS:
//      (in) pMsg - Pointer to the message to translate.
//		(in) wID  - Command ID value corresponding to the keystroke in the
//					container provided accelerator table.
//
//  RETURN VALUE:
//      Returns an HRESULT signifying success or failure.
//

HRESULT QOleInPlaceFrame::TranslateAccelerator( LPMSG pMsg, WORD wID )
{
    //DebugTrace(TEXT("QOleInPlaceFrame::TranslateAccelerator.\r\n"));
    if ( !pMsg )
        return E_INVALIDARG;

    ///suspended
    ///if (!::TranslateAccelerator(m_hwndFrame, g_pDoc->GetInPlaceAccel(), pMsg))
    ///  return (S_FALSE);

    return S_OK;
}

/////////////////////////////////////////////////////////////////////////////
// UI Helpers
//


//
//  FUNCTION:   QOleInPlaceFrame::ShowUIAndTools
//
//  PURPOSE:    Shows or hides the application's menu and/or tools.  This
//				is called as in-place objects are activated and deactivated.
//
//  PARAMETERS:
//      (in) fShow - TRUE if the app should show it's own UI and tools
//		(in) fMenu - TRUE if the app should show it's own menu
//
//  RETURN VALUE:
//      Returns an HRESULT signifying success or failure.
//
//  COMMENTS:
//		fShow will be FALSE if we should hide our own tools.  We don't
//		currently have any tools so for now we just ignore this.
//

void QOleInPlaceFrame::ShowUIAndTools( BOOL fShow, BOOL fMenu )
{
    //DebugTrace(TEXT("QOleInPlaceFrame::ShowUIAndTools.\r\n"));
    if ( fShow )
    {
        //
        // First reset the menu if necessary.
        //
        if ( fMenu )
            this->SetMenu( nullptr, nullptr, nullptr );

        //
        // Also redraw any tools we had hidden.
        //

        ///g_pToolbar->Show(TRUE);
    }
    else
    {
        ///g_pToolbar->Show(FALSE);
    }
}


//
//  FUNCTION:   QOleInPlaceFrame::ReinstateUI
//
//  PURPOSE:    Restores the applications tools after an object has
//				been deactivated.
//

void QOleInPlaceFrame::ReinstateUI( void )
{
    RECT rc;
    //DebugTrace(TEXT("QOleInPlaceFrame::ReinstateUI.\r\n"));

    //
    // Set the default border widths
    //
    SetRect( &rc, 0, 0 /* g_pToolbar->GetHeight()*/, 0, 0 );
    SetBorderSpace( &rc );

    //
    // Show our menu and tools
    //
    ShowUIAndTools( TRUE, TRUE );
}





//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////
// IUnknown Interface members
//

HRESULT QOleCallback::QueryInterface( REFIID riid, LPVOID * ppv )
{
    if ( !ppv ) 	return E_POINTER;

    *ppv = nullptr;

    if ( riid == IID_IRichEditOleCallback ) *ppv =  ( IRichEditOleCallback * )this;

    if ( riid == IID_IUnknown ) *ppv =  ( IUnknown * )this;


    if ( *ppv )  AddRef();

    return E_NOINTERFACE;
}

ULONG QOleCallback::AddRef( void )
{
    m_cRef++;
    //DebugCount(TEXT("QOleCallback::AddRef().  Count = %d.\r\n"),  m_cRef);
    return m_cRef;
}

ULONG QOleCallback::Release( void )
{
    m_cRef--;
    //DebugCount(TEXT("QOleCallback::Release().  Count = %d.\r\n"),  m_cRef);

    if ( 0 == m_cRef )
        delete this;

    return m_cRef;
}


/////////////////////////////////////////////////////////////////////////////
// IRichEditOleCallback Interface Members
//

//
//  FUNCTION:   QOleCallback::GetNewStorage
//
//  PURPOSE:    Gets a storage for a new object.
//
//  PARAMETERS:
//      ppStg - Where to return the storage.
//
//  RETURN VALUE:
//      Returns an HRESULT signifying success or failure.
//
//  COMMENTS:
//      Implemented in the document object.
//


//by Costel
HRESULT QOleCallback::GetNewStorage( LPSTORAGE * ppStg )
{
    //DebugTrace(TEXT("QOleCallback::GetNewStorage()\r\n"));

    if ( !ppStg )   return E_INVALIDARG;

    *ppStg = nullptr;

    //
    // We need to create a new storage for an object to occupy.  We're going
    // to do this the easy way and just create a storage on an HGLOBAL and let
    // OLE do the management.  When it comes to saving things we'll just let
    // the RichEdit control do the work.  Keep in mind this is not efficient,
    // but this program is just for demonstration.
    //

    ILockBytes * pLockBytes = nullptr;
    HRESULT hr = CreateILockBytesOnHGlobal( nullptr, TRUE, &pLockBytes );

    if ( FAILED( hr ) )
        return hr;

    ASSERT( pLockBytes );

    //STGM_READWRITE
    // doar STGM_WRITE nu merge paste din paint
    hr = StgCreateDocfileOnILockBytes( pLockBytes, STGM_SHARE_EXCLUSIVE | STGM_CREATE | STGM_WRITE, 0, ppStg );
    pLockBytes->Release();
    return ( hr );

    //return m_pDoc->GetNewStorage(ppStg);
}


//
//  FUNCTION:   QOleCallback::GetInPlaceContext
//
//  PURPOSE:    Gets the context information for an in place object.
//
//  PARAMETERS:
//      ppFrame    - Pointer to the frame window object.
//		ppDoc      - Pointer to the document window object.
//		pFrameInfo - Pointer to the frame window information.
//
//  RETURN VALUE:
//      Returns an HRESULT signifying success or failure.
//
//

HRESULT QOleCallback::GetInPlaceContext( LPOLEINPLACEFRAME * ppFrame,
        LPOLEINPLACEUIWINDOW * ppDoc,
        LPOLEINPLACEFRAMEINFO pFrameInfo )
{
    //DebugTrace(TEXT("QOleCallback::GetInPlaceContext()\r\n"));

    //
    // Validate the arguments
    //
    if ( !ppFrame || !ppDoc || !pFrameInfo )
    {
        //DebugMsg(TEXT("QOleCallback::GetInPlaceContext() received an  invalid argument.\r\n"));
        return E_INVALIDARG;
    }

    //
    // Return the appropriate interface pointers.
    //

    *ppFrame = nullptr;//m_pDoc->GetInPlaceFrame();

    if ( *ppFrame )
        ( *ppFrame )->AddRef();

    *ppDoc = ( LPOLEINPLACEUIWINDOW ) nullptr; // m_pDoc->GetInPlaceFrame();

    if ( *ppDoc )
        ( *ppDoc )->AddRef();


    //
    // Fill in the default frame window information.
    //
    pFrameInfo->fMDIApp = FALSE;
    pFrameInfo->hwndFrame = nullptr;//m_pDoc->GetFrameWindow();
    pFrameInfo->haccel = nullptr;//m_pDoc->GetInPlaceAccel();

    //
    // Note: CopyAcceleratorTable() returns the number of items in the table
    // 	     if the	lpAccelDest is nullptr.
    //
    pFrameInfo->cAccelEntries = CopyAcceleratorTable( pFrameInfo->haccel, nullptr, 0 );

    return S_OK;
}


//
//  FUNCTION:	QOleCallback::ShowContainerUI
//
//  PURPOSE:	Handles the showing or hiding of the container UI.
//
//  PARAMETERS:
//      fShow - TRUE if the function should display the UI, FALSE to hide it.
//
//  RETURN VALUE:
//      Returns an HRESULT signifying success or failure.
//

HRESULT QOleCallback::ShowContainerUI( BOOL fShow )
{
    //DebugTrace(TEXT("QOleCallback::ShowContainerUI()\r\n"));



    /*
    	if (!m_pDoc->GetInPlaceFrame()) 	// This should never fail, but just in case...
    		return E_FAIL;

    	if (fShow)
    	{
    		(m_pDoc->GetInPlaceFrame())->ReinstateUI();
    		//SetFocus(m_hwndEdit);
    	}
    	else
    		(m_pDoc->GetInPlaceFrame())->ShowUIAndTools(FALSE, FALSE);

    */
    return S_OK;
}


//
//  FUNCTION:	QOleCallback::QueryInsertObject
//
//  PURPOSE:    Called to ask whether an object should be inserted.  We're
//				going to allow everything to be inserted.
//

HRESULT QOleCallback::QueryInsertObject( LPCLSID /* pclsid */,
        LPSTORAGE /* pStg */,
        LONG /* cp */ )
{
    //DebugTrace(TEXT("QOleCallback::QueryInsertObject()\r\n"));
    return S_OK;
}


//
//  FUNCTION:   QOleCallback::DeleteObject
//
//  PURPOSE:    Notification that an object is going to be deleted.
//

HRESULT QOleCallback::DeleteObject( LPOLEOBJECT /* pOleObj */ )
{
    //DebugTrace(TEXT("QOleCallback::DeleteObject()\r\n"));
    return S_OK;
}


//
//  FUNCTION:   QOleCallback::QueryAcceptData
//
//  PURPOSE:    Called to ask whether the data that is being pasted or
//				dragged should be accepted.  We accept everything.
//

HRESULT QOleCallback::QueryAcceptData( LPDATAOBJECT /* pDataObj */,
                                       CLIPFORMAT * /* pcfFormat */,
                                       DWORD /* reco */,
                                       BOOL /* fReally */,
                                       HGLOBAL /* hMetaPict */ )
{
    //DebugTrace(TEXT("QOleCallback::QueryAcceptData()\r\n"));
    return S_OK;
}


//
//  FUNCTION:   QOleCallback::ContextSensitiveHelp
//
//  PURPOSE:    Tells the application that it should transition into or out of
//				context sensitive help mode.  We don't implement help at all
//				so blow this off.
//

HRESULT QOleCallback::ContextSensitiveHelp( BOOL fEnterMode )
{
    //DebugTrace(TEXT("QOleCallback::ContextSensitveHelp()\r\n"));
    return E_NOTIMPL;
}


//
//  FUNCTION:   QOleCallback::GetClipboardData
//
//  PURPOSE:    Called when the rich edit needs to provide clipboard data.
//				We'll let the rich edit control handle this one.
//

HRESULT QOleCallback::GetClipboardData( CHARRANGE * /* pchrg */,
                                        DWORD /* reco */,
                                        LPDATAOBJECT * ppDataObject )

{
    //DebugTrace(TEXT("QOleCallback::GetClipboardData()\r\n"));
    *ppDataObject = nullptr;
    return E_NOTIMPL;
}


//
//  FUNCTION:   QOleCallback::GetDragDropEffect
//
//  PURPOSE:    Allows us to determine the drag cursor effect when the user
//				is dragging something over us.  We'll let the rich edit control
//				handle this one as well.
//

HRESULT QOleCallback::GetDragDropEffect( BOOL /* fDrag */,
        DWORD /* grfKeyState */,
        LPDWORD /* pdwEffect */ )
{
    //DebugTrace(TEXT("QOleCallback::GetDragDropEffect()\r\n"));
    return E_NOTIMPL;
}


//
//  FUNCTION:   QOleCallback::GetContextMenu
//
//  PURPOSE:    Creates the context menu for alternate mouse clicks in the
//				RichEdit control.
//
//  PARAMETERS:
//      seltype - Selection type
//		pOleObj - IOleObject interface of the selected object, if any
//		pchrg   - Selection range
//		phMenu  - Place to return the constructed menu
//
//  RETURN VALUE:
//      Returns an HRESULT signifying success or failure.
//

HRESULT QOleCallback::GetContextMenu( WORD seltype, LPOLEOBJECT pOleObj, CHARRANGE * pchrg,	 HMENU * phMenu )
{
    //HMENU hMenuVerbs = nullptr;

    ////DebugTrace(TEXT("QOleCallback::GetContextMenu()\r\n"));

    ////
    //// First create the menu.
    ////
    //*phMenu = CreatePopupMenu();
    //if (!*phMenu)
    //	return E_FAIL;

    ////
    //// Now put the verbs on the menu if we have a selected object.
    ////
    //if (pOleObj)
    //{
    //	OleUIAddVerbMenu(pOleObj, nullptr, *phMenu, 0, IDM_VERBMIN, IDM_VERBMAX, TRUE, ID_EDIT_CONVERT, &hMenuVerbs);

    //	AppendMenu(*phMenu, MF_SEPARATOR, 0, nullptr);
    //}

    ////
    //// If there isn't anything selected, then gray out the cut and copy
    //// menu items.
    ////
    //UINT mf = MF_STRING | MF_BYCOMMAND;
    //mf |= (pchrg->cpMin == pchrg->cpMax ? MF_GRAYED : MF_ENABLED);

    ////
//   // Add the cut, copy, and paste verbs.
    ////
    //AppendMenu(*phMenu, mf, ID_EDIT_CUT, TEXT("Cu&t"));
    //AppendMenu(*phMenu, mf, ID_EDIT_COPY, TEXT("&Copy"));

    ////
    //// Now decide if there is something that can be pasted into the Rich Edit
    //// control.
    ////
    //mf = MF_STRING | MF_BYCOMMAND;
    //mf |= (SendMessage(m_hwndEdit, EM_CANPASTE, 0, 0) ? MF_ENABLED : MF_GRAYED);
    //AppendMenu(*phMenu, mf, ID_EDIT_PASTE, TEXT("&Paste"));

    return S_OK;
}
